(function($) {
    /**
     * 用于异步加载Google Map API.
     */
    ujs.define('GoogleMapAPI', 'ujs.subjects.map', {
        //google map api及扩展api是否已加载完成.
        isLoaded : false,
        //加载地图api时，显示模式层的区域。
        maskZone : document.body,
        //google map base api.
        api : 'https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&libraries=places&callback=ujs.subjects.map.GoogleMapAPI.lastMapCallback',
        /**
         * 扩展api. 当base api加载完成后，依次加载扩展api.           
         */
        subApi : [],
        /**
         * 当前使用的google map回调. 
         */
        currentCallback : Function.empty,
        /**
         * google map base api加载完成后的回调. 
         */
        lastMapCallback : function(){
            var _this = this,
                subApi = this.subApi,
                subApiPromise = [];
            //加载扩展api.
            for(var i=0; i<subApi.length; i++){
                subApiPromise.push($.Deferred(function( defer ) {
                    //TODO: 这种做法受跨域请求影响，wallboard系统请求不到， 所以暂时禁用subAPI.
                    $.ajax({
                        url : subApi[i],
                        processUrl : false
                    }).then( defer.resolve, defer.reject );
                }).promise());
            }             
            $.when.apply($, subApiPromise).done(function(){
                _this.isLoaded = true;
                /**
                 * 默认map配置. 
                 */
                _this.mapDefConfig = {
                    streetViewControl: false,
                    mapTypeId : google.maps.MapTypeId.ROADMAP,
                    mapTypeControl : false,
                    navigationControlOptions : {
                        style : google.maps.NavigationControlStyle.SMALL
                    }
                };                
                ujs.ui.paneMask.hide(_this.maskZone);
                _this.currentCallback();
            });
        },
        /**
         * @method load
         * 加载google map api,并且加载完成后执行指定的回调函数；
         * 若google map api已加载，则直接执行回调。
         * 若未指定回函数，则仅加载google map api。
         * @param maskZone {Element} 加载地图api时，显示模式层的区域，默认document.body。 
         */
        load : function(cb, maskZone) {
            var _this = this;
            if(maskZone){
                this.maskZone  = maskZone;
            }
            _this.currentCallback = Type.isFunction(cb) ? cb : Function.empty;
            if (!this.isLoaded) {                
                ujs.ui.paneMask.show(_this.maskZone, 'loading');
                ujs.loadScript(_this.api, Function.empty, function(){
                    ujs.ui.paneMask.hide(_this.maskZone);
                    bubble.msg('Google map api load failed.');
                });
            } else {
                _this.currentCallback();
            }
        },
        /**
         * Google map实用工具方法. 
         */
        util : {
            /**
             * @method getPlaces
             * 获取指定坐标的可读地址。
             * @param {LatLng} latLng
             * @param {Function} cb(addrs, addr)
             */
            getPlaces : function(latLng, cb, errorFun){
                var geocoder = new google.maps.Geocoder();                
                geocoder.geocode({'latLng': latLng}, function(results, status){                    
                    if (status == google.maps.GeocoderStatus.OK) {
                        if (results[0] && cb) { 
                            cb(results, results[0]['formatted_address']);
                        }
                    } else {
                        if(Type.isFunction(errorFun)){
                            errorFun(status, latLng);
                        }
                    }
                });
            },
            /**
             * 在地图上添加搜索框.
             * @param {Map} map
             * @param {Object} searchBoxCfg
             * @param {Object} markerCfg
             * @param {Object} markerHandlers
             */
            addSeachBox : function(map, searchBoxCfg, markerCfg, markerHandlers){
                map.__searchedMarkers = []; //存放搜索到的位置标注marker.                
                var $searchBox = $('<input type="text" placeholder="{placeholder}" />'.format(searchBoxCfg));
                //添加搜索框样式.
                $searchBox.addClass(searchBoxCfg['cls']);                
                map.controls[searchBoxCfg['position'] || google.maps.ControlPosition.TOP_LEFT].push($searchBox.get(0));
        
                var googleSearchBox = new google.maps.places.SearchBox($searchBox.get(0));        
                google.maps.event.addListener(googleSearchBox, 'places_changed', function() {
                    var places = googleSearchBox.getPlaces();
                    //清除地图上的已存在marker.
                    for (var i = 0, marker; marker = map.__searchedMarkers[i]; i++) {
                        marker.setMap(null);
                    }                    
                    map.__searchedMarkers = [];
                    var bounds = new google.maps.LatLngBounds();
                    for (var i = 0, place; place = places[i]; i++) {
                        var marker = new google.maps.Marker($.extend({},{  
                            map : map,
                            title : place.name,
                            url : place.icon,
                            position : place.geometry.location
                        }, markerCfg));
                        (function(place, marker) {
                            var markerInitalHandler = markerHandlers['inital'];
                            if(Type.isFunction(markerInitalHandler)){
                                markerInitalHandler.call(marker, place);
                            }
                            //marker点击事件.
                            google.maps.event.addListener(marker, 'click', function() {                                
                                var markerClickHandler = markerHandlers['click'];
                                if(Type.isFunction(markerClickHandler)){
                                    markerClickHandler.call(this, place);
                                }
                            });
                        })($.extend(true, {}, place), marker);
        
                        map.__searchedMarkers.push(marker);
                        bounds.extend(place.geometry.location);
                    }
                    map.fitBounds(bounds);
                });
                google.maps.event.addListener(map, 'bounds_changed', function() {                    
                    googleSearchBox.setBounds(map.getBounds());
                });
                return googleSearchBox;
            }
        }
    });
})(jQuery);